<?php

namespace qgauth\datascope;

use yii\db\Query;
use yii\db\conditions\OrCondition;
use yii;

/**
 * 此trait 要在baseModel中use或者在EsActiveRecordList类中use
 * 设置了数据权限标识，就会根据用户的角色以及设置的数据权限
 * 中往query中追加sql的where条件
 */
trait DataScope
{
    public $data_scope_flag = "";

    public function getTablePrefix()
    {
        return \Yii::$app->db->tablePrefix;
    }

    /**
     * 设置数据权限的标记，设置了，就认为开启了数据权限过滤
     * @param $flag
     * @return $this
     */
    public function setDataScopeFlag($flag)
    {
        $this->data_scope_flag = $flag;

        // 获取权限范围
        $data_scope = $this->getDataScope(\Yii::$app->controller->_user->id, $flag);
        //为空时即拥有全部权限，不用过滤
        if (!$data_scope) {
            return $this;
        }

        //根据权限增加筛选条件
        foreach ($data_scope as $value) {
            if (!empty($value['user_id_list'])) {
                if (method_exists($this, 'andWhere')) {
                    //有别名的获取主表别名
                    list($table_name, $alias) = $this->getTableNameAndAlias();
                    $table_name = empty($alias) ? $this->getTablePrefix() . $value['data_table'] : $alias;
                    $this->andWhere([$table_name . "." . $value['data_field'] => $value['user_id_list']]);
                } else {
                    $this->setAndFilterWhere([$this->getTablePrefix() . $value['data_table'] . "." . $value['data_field'] => $value['user_id_list']]);
                }
            }
        }

        return $this;
    }

    /**
     * 通过用户id和数据权限标记来查询数据全新啊
     * 返回该用户有权限查询的用户id列表
     * 考虑到性能问题，返回空数组，就相当拥有查看全部的权限，不需要in全部员工的用户id
     *
     * @param $user_id
     * @param $flag
     * @return array
     */
    public function getDataScope($user_id, $flag)
    {
        $data_scope  = [];

        $department_role_user_list = (new Query())
            ->select(['role_id'])
            ->from($this->getTablePrefix() . 'department_role_user')
            ->where(['is_delete' => 0, 'user_id' => $user_id])
            ->groupBy('role_id')
            ->all();

        $role_id_list = array_column($department_role_user_list,  'role_id');
        $role_data_scope_list = (new Query())
            ->select(['role_id', 'scope', 'data_table', 'data_field'])
            ->from($this->getTablePrefix() . 'role_data_scope')
            ->where(['role_id' => $role_id_list, 'flag' => $flag, 'status' => 1, 'is_delete' => 0])
            ->all();

        //根据数据源和字段分组，因为可能对不同的角色设置的相同的数据源判断，只是权限范围可能不一样
        $group_role_data_scope_list = [];
        $exist_role_id_list = [];
        $has_department = false; //只要有一个权限有部门的，后续有可能要查询部门，需要获取部门数据
        foreach ($role_data_scope_list as $role_data_scope) {
            if (!in_array($role_data_scope['role_id'], $exist_role_id_list)) {
                $exist_role_id_list[] = $role_data_scope['role_id'];
            }
            if ($role_data_scope['scope'] == 1) {
                $has_department = true;
            }

            $group_key = $role_data_scope['data_table'] . "@" . $role_data_scope['data_field'];
            if (!isset($group_role_data_scope_list[$group_key])) {
                $group_role_data_scope_list[$group_key] = $role_data_scope['scope'];
            } else { // 保留权限范围更大的
                if ($group_role_data_scope_list[$group_key] > $role_data_scope['scope']) {
                    $group_role_data_scope_list[$group_key] = $role_data_scope['scope'];
                }
            }
        }

        //如果这个用户存在没有设置数据权限的角色，那么就可以查看所有数据，因为数据权限默认是全开放
        if (!empty(array_diff($role_id_list, $exist_role_id_list))) {
            return $data_scope;
        }

        //所有相关部门id，因为一个人可能有多个部门，所以干脆直接取出所有部门数据，避免多次请求数据库
        $related_dept_list = [];
        $related_user_id_list = [];
        if ($has_department) {
            //获取部门以及所有下级部门
            $dingtalk_department_list = (new Query())
                ->select(['dept_id', 'parent_id'])
                ->from($this->getTablePrefix() . 'dingtalk_department')
                ->where(['is_delete' => 0])
                ->all();

            foreach (\Yii::$app->controller->_user->dept_id_list as $dept_id) {
                //本部门
                $related_dept_list[] = $dept_id;

                //下属部门
                $child_list = [];
                $this->getChildren($dingtalk_department_list, $dept_id, $child_list);
                $related_dept_list = array_merge($related_dept_list, $child_list);
            }

            //构建Json查询数组
            $json_search_list = [];
            foreach ($related_dept_list as $dept_id) {
                $json_search_list[] = "JSON_CONTAINS(dept_id_list, '" . $dept_id . "')";
            }

            //拉出关联部门的用户
            $related_user_list = (new Query())
                ->select(['id'])
                ->from($this->getTablePrefix() . 'user')
                ->where(['is_delete' => 0])
                ->andWhere(new OrCondition($json_search_list))
                ->all();
            $related_user_id_list = array_column($related_user_list, 'id');
        }

        //根据数据源来分数组权限
        foreach ($group_role_data_scope_list as $group_key => $scope) {
            list($data_table, $data_field) = explode("@", $group_key);
            $user_id_list = [];
            if ($scope == 1) { //部门及下属
                $user_id_list = $related_user_id_list;
            }

            if ($scope == 2) { //自己
                $user_id_list = [$user_id];
            }

            $data_scope[] = ['data_table' => $data_table, 'data_field' => $data_field, 'user_id_list' => $user_id_list];
        }

        return $data_scope;
    }

    public function getChildren(array $data, $parentId, &$children = [])
    {
        foreach ($data as $item) {
            if ($item['parent_id'] == $parentId) {
                $children[] = $item;
                $this->getChildren($data, $item['dept_id'], $children);
            }
        }
        return $children;
    }

}